use anyhow::{anyhow, Result};
use umya_spreadsheet::{
    self as umya, Border, Color, Font, FontName, HorizontalAlignmentValues, PatternFill,
};

pub trait CSWSheetStyle {
    fn set_sheet_col_width_ez(&mut self, col_index: u32, width: f64) -> Result<()>;
    fn set_sheet_col_widths_ez(&mut self, start_col_index: u32, col_widths: &[f64]) -> Result<()>;
    fn set_sheet_row_height_ez(&mut self, row_index: u32, height: f64) -> Result<()>;
    fn set_sheet_row_heights_ez(&mut self, start_row_index: u32, row_heights: &[f64])
        -> Result<()>;
}

impl CSWSheetStyle for umya::structs::Worksheet {
    fn set_sheet_col_width_ez(&mut self, col_index: u32, width: f64) -> Result<()> {
        self.get_column_dimension_by_number_mut(&(col_index))
            .set_width(width);
        Ok(())
    }

    fn set_sheet_col_widths_ez(&mut self, start_col_index: u32, col_widths: &[f64]) -> Result<()> {
        col_widths
            .iter()
            .enumerate()
            .try_for_each(|(i, &width)| -> Result<()> {
                self.set_sheet_col_width_ez(i as u32 + start_col_index, width)
            })
    }

    fn set_sheet_row_height_ez(&mut self, row_index: u32, height: f64) -> Result<()> {
        self.get_row_dimension_mut(&row_index).set_height(height);
        Ok(())
    }

    fn set_sheet_row_heights_ez(
        &mut self,
        start_row_index: u32,
        row_heights: &[f64],
    ) -> Result<()> {
        row_heights
            .iter()
            .enumerate()
            .try_for_each(|(i, &width)| -> Result<()> {
                self.set_sheet_col_width_ez(i as u32 + start_row_index, width)
            })
    }
}

pub trait CSWStyle {
    fn set_font_ez(
        &mut self,
        font_name: &str,
        font_size: f64,
        bold: bool,
        italic: bool,
    ) -> Result<()>;
    fn set_borders_ez(&mut self, border_type: &str) -> Result<()>;
    fn set_alignment_ez(&mut self, hor_align: &str, ver_align: &str, wrap: bool) -> Result<()>;
    fn set_cell_color(&mut self, cell_color: &str) -> Result<()>;
    fn set_number_format_ez(&mut self, format_id: u32) -> Result<()>;
}

impl CSWStyle for umya::Style {
    fn set_font_ez(
        &mut self,
        font_name: &str,
        font_size: f64,
        bold: bool,
        italic: bool,
    ) -> Result<()> {
        let mut font = Font::default();
        let mut fontname = FontName::default();
        fontname.set_val(font_name);
        font.set_font_name(fontname)
            .set_size(font_size)
            .set_bold(bold)
            .set_italic(italic);
        self.set_font(font);
        Ok(())
    }
    fn set_borders_ez(&mut self, border_type: &str) -> Result<()> {
        let borders = self.get_borders_mut();
        let mut border = Border::default();
        border.set_border_style(border_type);
        borders.set_left_border(border.clone());
        borders.set_right_border(border.clone());
        borders.set_top_border(border.clone());
        borders.set_bottom_border(border);
        Ok(())
    }
    fn set_alignment_ez(&mut self, hor_align: &str, ver_align: &str, wrap: bool) -> Result<()> {
        let ali = self.get_alignment_mut();
        let horizontal_align = hor_align
            .parse::<HorizontalAlignmentValues>()
            .map_err(|()| anyhow!("Invalid alignment value"))?;
        ali.set_horizontal(horizontal_align);

        let vertical_align = ver_align
            .parse::<umya::VerticalAlignmentValues>()
            .map_err(|()| anyhow!("Invalid alignment value"))?;
        ali.set_vertical(vertical_align);

        ali.set_wrap_text(wrap);

        Ok(())
    }
    fn set_cell_color(&mut self, cell_color: &str) -> Result<()> {
        let fill = self.get_fill_mut();
        let mut pattern_fill = PatternFill::default();
        let mut fg = Color::default();
        fg.set_argb(cell_color);
        pattern_fill.set_foreground_color(fg);
        fill.set_pattern_fill(pattern_fill);
        Ok(())
    }
    fn set_number_format_ez(&mut self, format_id: u32) -> Result<()> {
        let num_format = self.get_number_format_mut();
        num_format.set_number_format_id(format_id);
        Ok(())
    }
}
